import subprocess
import os
import json
import subprocess
from common import ffmpeg_executable_cmd, ffprobe_executable_cmd


class AudioConverter:
    """音频转换器"""
    
    def __init__(self):
        pass
    
    def is_valid_audio_file(self, file_path):
        """使用ffprobe检测文件是否为有效的音频文件"""
        try:
            ffprobe_cmd = [
                ffprobe_executable_cmd,
                "-v", "quiet",
                "-print_format", "json",
                "-show_streams",
                "-select_streams", "a:0",  # 只选择第一个音频流
                file_path
            ]
            
            output = subprocess.check_output(ffprobe_cmd, stderr=subprocess.STDOUT)
            probe_data = json.loads(output.decode())
            
            # 检查是否有音频流
            if 'streams' in probe_data and len(probe_data['streams']) > 0:
                stream = probe_data['streams'][0]
                # 确认是音频流
                if stream.get('codec_type') == 'audio':
                    return True
            
            return False
            
        except (subprocess.CalledProcessError, json.JSONDecodeError, Exception):
             return False
    
    def _get_output_path(self, input_path, suffix="_converted", extension=None):
        """生成输出文件路径"""
        base, ext = os.path.splitext(input_path)
        if extension:
            ext = f".{extension}"
        return f"{base}{suffix}{ext}"

    def convert_audio(self, input_path, output_format="wav"):
        """转换音频文件"""
        # 音频格式配置
        audio_configs = {
            "wav": {
                "ext": ".wav",
                "args": ["-codec:a", "pcm_s16le", "-ar", "16000"]
            },
            "mp3": {
                "ext": ".mp3",
                "args": ["-codec:a", "libmp3lame", "-b:a", "192k", "-ar", "44100"]
            },
            "aac": {
                "ext": ".aac",
                "args": ["-codec:a", "aac", "-b:a", "128k", "-ar", "44100"]
            },
            "flac": {
                "ext": ".flac",
                "args": ["-codec:a", "flac", "-compression_level", "5"]
            },
            "ogg": {
                "ext": ".ogg",
                "args": ["-codec:a", "libvorbis", "-q:a", "5"]
            },
            "m4a": {
                "ext": ".m4a",
                "args": ["-codec:a", "aac", "-b:a", "128k", "-ar", "44100"]
            }
        }

        if output_format not in audio_configs:
            raise Exception(f"不支持的音频格式：{output_format}")

        config = audio_configs[output_format]
        output_file = self._get_output_path(input_path, extension=output_format)

        # 构建ffmpeg命令
        ffmpeg_cmd = [
            ffmpeg_executable_cmd,
            "-i", input_path,
            "-vn",  # 禁用视频流，只处理音频
            "-map", "0:a:0"  # 选择第一个音频流
        ] + config["args"] + [
            "-avoid_negative_ts", "make_zero",  # 避免负时间戳
            "-y",  # 覆盖输出文件
            output_file
        ]

        try:
            # 首先检查输入文件是否为有效音频
            if not self.is_valid_audio_file(input_path):
                raise Exception(f"输入文件不是有效的音频文件: {os.path.basename(input_path)}")
            
            subprocess.check_output(ffmpeg_cmd, stderr=subprocess.STDOUT)
            
            # 检查输出文件是否成功创建
            if not os.path.exists(output_file):
                raise Exception(f"转换失败：输出文件未生成")
            
            return output_file
        except subprocess.CalledProcessError as e:
            error_output = e.output.decode() if e.output else "未知错误"
            filename = os.path.basename(input_path)
            
            # 提取更有用的错误信息
            if "Invalid data found" in error_output or "could not find codec parameters" in error_output:
                raise Exception(f"文件格式错误或文件损坏: {filename}")
            elif "No such file" in error_output:
                raise Exception(f"文件不存在: {filename}")
            elif "Permission denied" in error_output:
                raise Exception(f"文件访问权限不足: {filename}")
            elif "Stream map '0:a:0' matches no streams" in error_output:
                raise Exception(f"文件中没有音频流: {filename}")
            elif "Encoder not found" in error_output:
                raise Exception(f"不支持的音频编码器: {filename}")
            elif "Protocol not found" in error_output:
                raise Exception(f"不支持的文件协议: {filename}")
            elif "Operation not permitted" in error_output:
                raise Exception(f"操作被系统拒绝: {filename}")
            elif "Disk full" in error_output or "No space left" in error_output:
                raise Exception(f"磁盘空间不足: {filename}")
            else:
                # 尝试提取更具体的错误信息
                lines = error_output.split('\n')
                error_line = None
                for line in lines:
                    if 'error' in line.lower() or 'failed' in line.lower():
                        error_line = line.strip()
                        break
                
                if error_line:
                    raise Exception(f"音频转换失败: {filename}\n错误: {error_line}")
                else:
                    raise Exception(f"音频转换失败: {filename}\n详细错误: {error_output[:200]}...")